
#include "net.h"
#include "scripting.h"

using namespace WtfEngine;
using namespace boost::python;

BOOST_PYTHON_MODULE(WtfNet)
{
	/**** Sockets interface ****/

	class_<IPacket, IPacket::tRef, boost::noncopyable>("IPacket", no_init)
		.add_property("size", &IPacket::getSize)
	;

	class_<IpAddress>("IpAddress", init<unsigned int>())
		.def(init<unsigned char, unsigned char, unsigned char, unsigned char>())
	;
	implicitly_convertible<IpAddress, unsigned int>();

	class_<ISocket, ISocket::tRef, boost::noncopyable>("ISocket", no_init)
		.def("Listen", &ISocket::Listen)
		.def("Connect", &ISocket::Connect)
		.def("Disconnect", &ISocket::Disconnect)

		.def("SendPacket", &ISocket::SendPacket)
		.def("RecvPacket", &ISocket::RecvPacket)

		.def("Destroy", &ISocket::Destroy)

		.add_property("address", &ISocket::getIpAddress)
		.add_property("port", &ISocket::getPort)
	;

	/**** Socket Events ****/

	class_<SocketEvent, SocketEvent::tRef, bases<Event> >("SocketEvent", init<const ISocket::tRef&>())
		.add_property("socket", &SocketEvent::getSocket)
	;
	implicitly_convertible<SocketEvent::tRef, Event::tRef>();

	class_<SocketDataEvent, SocketDataEvent::tRef, bases<SocketEvent> >("SocketDataEvent", init<const ISocket::tRef&>())
	;
	implicitly_convertible<SocketDataEvent::tRef, SocketEvent::tRef>();

	class_<SocketStatusChangeEvent, SocketStatusChangeEvent::tRef, bases<SocketEvent> >("SocketStatusChangeEvent", init<const ISocket::tRef&>())
	;
	implicitly_convertible<SocketStatusChangeEvent::tRef, SocketEvent::tRef>();

	class_<SocketStatusChangeTo, SocketStatusChangeTo::tRef, bases<SocketStatusChangeEvent> >("SocketStatusChangeTo", init<const ISocket::tRef&, ISocket::tStatus>())
		.add_property("socketStatus", &SocketStatusChangeTo::getStatus)
	;
	implicitly_convertible<SocketStatusChangeTo::tRef, SocketStatusChangeEvent::tRef>();

	class_<SocketConnectEvent, SocketConnectEvent::tRef, bases<SocketStatusChangeTo> >("SocketConnectEvent", init<const ISocket::tRef&>())
	;
	implicitly_convertible<SocketConnectEvent::tRef, SocketStatusChangeTo::tRef>();

	class_<SocketCloseEvent, SocketCloseEvent::tRef, bases<SocketStatusChangeTo> >("SocketCloseEvent", init<const ISocket::tRef&>())
	;
	implicitly_convertible<SocketCloseEvent::tRef, SocketStatusChangeTo::tRef>();

	class_<SocketClientConnectEvent, SocketClientConnectEvent::tRef, bases<SocketEvent> >("SocketClientConnectEvent", init<const ISocket::tRef&>())
		.add_property("newSocket", &SocketClientConnectEvent::getNewSocket)
	;
	implicitly_convertible<SocketClientConnectEvent::tRef, SocketEvent::tRef>();


	/**** Sockets Implementation ****/

	class_<TcpSocket, TcpSocket::tRef, bases<ISocket>, boost::noncopyable>("TcpSocket", init<tPort>())
	;
	implicitly_convertible<TcpSocket::tRef, ISocket::tRef>();

	class_<UdpSocket, UdpSocket::tRef, bases<ISocket>, boost::noncopyable>("UdpSocket", init<tPort>())
	;
	implicitly_convertible<UdpSocket::tRef, ISocket::tRef>();

	class_<UdpBroadcastSocket, UdpBroadcastSocket::tRef, bases<UdpSocket>, boost::noncopyable>("UdpBroadcastSocket", init<tPort>())
	;
	implicitly_convertible<UdpBroadcastSocket::tRef, ISocket::tRef>();


	/**** Packets ****/

	class StringPacketWrapper: public NonCopyPacket {
		public:
			StringPacketWrapper(const std::string& s):
			  NonCopyPacket(new unsigned char[s.length()], s.length()) {
				for(int i = 0; i < s.length(); i++) {
					(*this)[i] = s[i];
				};
			};

		    GC_OBJECT(StringPacketWrapper, GC_ADDEDSIZE_AUTO(NonCopyPacket, StringPacketWrapper));
	};
	class_<StringPacketWrapper, StringPacketWrapper::tRef, bases<IPacket> >("StringPacket", init<const std::string&>())
	;
	implicitly_convertible<StringPacketWrapper::tRef, IPacket::tRef>();


	/**** Protocol - Net Messages ****/

	class_<PartyBroadcastMessage>("PartyBroadcastMessage")
		.def_readwrite("currentPartySize", &PartyBroadcastMessage::uCurrentPartySize)
	;

	class_<Packet<PartyBroadcastMessage>, GcReference<Packet<PartyBroadcastMessage> >, bases<IPacket> >
		("PartyBroadcastMessagePacket", init<const PartyBroadcastMessage&>())
		.add_property("msg", make_function((PartyBroadcastMessage * (Packet<PartyBroadcastMessage>::*)())
			&Packet<PartyBroadcastMessage>::getData, return_value_policy<reference_existing_object>()))
	;
};
